<template>
  <div class="smart-image-wrapper" :style="wrapperStyle">
    <!-- 模糊预览图 -->
    <img
      v-if="lowSrc"
      :src="lowSrc"
      class="preview-blur"
      :style="imageStyle"
      alt="preview"
    />

    <!-- 高清图 -->
    <el-image
      v-bind="attrs"
      :src="optimizedSrc"
      :fit="fit"
      :lazy="lazy"
      :preview-src-list="preview ? [realSrc] : []"
      class="hd-image"
      :style="[imageStyle, { opacity: loaded ? 1 : 0 }]"
      @load="handleLoad"
      @error="handleError"
    >
      <template #placeholder>
        <div
          class="flex items-center justify-center h-full text-gray-400 text-sm"
        >
          加载中...
        </div>
      </template>
      <template #error>
        <div
          class="flex items-center justify-center h-full text-red-400 text-sm"
        >
          加载失败
        </div>
      </template>
    </el-image>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, useAttrs, onMounted } from "vue";

interface Props {
  src: string;
  lowSrc?: string; // 低清预览图路径
  lazy?: boolean;
  preview?: boolean;
  fit?: "fill" | "contain" | "cover" | "none" | "scale-down";
  width?: string | number;
  height?: string | number;
  compress?: boolean;
  quality?: number;
  fallback?: string;
}

const props = withDefaults(defineProps<Props>(), {
  lazy: true,
  preview: false,
  fit: "cover",
  compress: true,
  quality: 0.7,
  fallback: "/default-image.png"
});

const attrs = useAttrs();
const realSrc = ref("");
const optimizedSrc = ref("");
const lowSrc = ref("");
const loaded = ref(false);

/** 容器样式 */
const wrapperStyle = computed(() => ({
  width: typeof props.width === "number" ? `${props.width}px` : props.width,
  height: typeof props.height === "number" ? `${props.height}px` : props.height,
  overflow: "hidden",
  position: "relative",
  display: "inline-block",
  background: "#f6f6f6"
}));

/** 图片样式 */
const imageStyle = computed(() => ({
  width: "100%",
  height: "100%",
  objectFit: props.fit
}));

/**
 * ✅ 路径解析：兼容 http(s)、@、相对路径、本地资源
 */
function resolveSrcPath(src: string): string {
  if (!src) return "";
  if (/^https?:\/\//.test(src)) return src;
  if (src.startsWith("@/")) {
    try {
      return new URL(src.replace(/^@/, "/src"), import.meta.url).href;
    } catch {
      console.warn("[SmartImage] 无法解析 @ 路径:", src);
    }
  }
  if (src.startsWith("./") || src.startsWith("../")) {
    try {
      return new URL(src, import.meta.url).href;
    } catch {
      console.warn("[SmartImage] 无法解析相对路径:", src);
    }
  }
  if (src.startsWith("/")) return src;
  return src;
}

/**
 * 压缩本地图片生成模糊预览或低质量图
 */
async function compressLocalImage(
  src: string,
  scale = 0.05,
  quality = 0.3
): Promise<string> {
  try {
    const blob = await fetch(src).then(r => {
      if (!r.ok) throw new Error("无法加载图片");
      return r.blob();
    });
    const bitmap = await createImageBitmap(blob);
    const canvas = document.createElement("canvas");
    canvas.width = bitmap.width * scale;
    canvas.height = bitmap.height * scale;
    const ctx = canvas.getContext("2d")!;
    ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
    return canvas.toDataURL("image/jpeg", quality);
  } catch (err) {
    console.warn("[SmartImage] 低清预览图生成失败:", err);
    return "";
  }
}

async function initImage() {
  const path = resolveSrcPath(props.src);
  realSrc.value = path;
  optimizedSrc.value = path;

  // 如果提供了 lowSrc（外部提供缩略图），优先使用
  if (props.lowSrc) {
    lowSrc.value = resolveSrcPath(props.lowSrc);
  } else {
    // 自动生成模糊缩略图（仅本地图片）
    if (!/^https?:\/\//.test(path)) {
      lowSrc.value = await compressLocalImage(path, 0.05, 0.3);
    }
  }

  // 预压缩主图（防止过大）
  if (!/^https?:\/\//.test(path) && props.compress) {
    optimizedSrc.value = await compressLocalImage(path, 1, props.quality);
  }
}

function handleLoad() {
  loaded.value = true;
}

function handleError() {
  console.warn("[SmartImage] 加载失败，使用 fallback");
  optimizedSrc.value = props.fallback;
}

onMounted(() => {
  initImage();
});
</script>

<style scoped>
.smart-image-wrapper {
  position: relative;
}

.preview-blur {
  position: absolute;
  top: 0;
  left: 0;
  filter: blur(20px);
  transform: scale(1.05);
  transition: opacity 0.4s ease;
  object-fit: cover;
  width: 100%;
  height: 100%;
  z-index: 1;
}

.hd-image {
  position: relative;
  z-index: 2;
  transition: opacity 0.6s ease;
}
</style>
